"""
Case Type   : 故障&可靠性测试
Case Name   : 构造待扩容备机节点空间不足，故障恢复后备机扩容成功
Create At   : 2022/4/8
Owner       : n@ningyali
Description :
    1、进行大文件构造，使待扩容备机磁盘空间不足
    2、备机扩容
    3、恢复备机故障
    4、备机扩容
    5、查看数据库集群状态
    6、查看主备数据
Expect      :
    1、故障注入成功
    2、备机扩容成功
    3、故障恢复成功
    4、备机扩容成功
    5、数据库集群状态正常
    6、数据一致
History     :
"""
import os
import re
import time
import unittest
from datetime import datetime

from yat.test import macro

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH, RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger


class GsExpansion22(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.sh = {'pri_root': CommonSH('PrimaryRoot'),
                   'pri_user': CommonSH(self.nodes_tuple[0]),
                   'sta1_root': CommonSH('Standby1Root'),
                   'sta1_user': CommonSH(self.nodes_tuple[1]),
                   'sta2_user': CommonSH(self.nodes_tuple[2])}
        self.node_num = self.sh['pri_user'].get_node_num()
        self.log = Logger()
        self.cons = Constant()
        self.com = Common()
        self.t_name = 't_expansion_22'
        text = f'-----{os.path.basename(__file__)} start-----'
        self.log.info(text)

        text = '-----预置步骤: 获取数据目录所在磁盘名 expect: 成功-----'
        self.log.info(text)
        cmd = f"df -h {macro.DB_INSTANCE_PATH}|grep -v Filesystem|" \
            f"awk '{{{{print $1}}}}'"
        self.disk_name = self.com.get_sh_result(self.sh['sta1_root'].node,
                                                cmd).strip()
        self.log.info(self.disk_name)
        self.assertIn('/dev', self.disk_name)

        text = '----预置步骤: 一主两备减容一备，后续用例才能扩容 expect: 成功----'
        self.log.info(text)
        expect_msg = 'Success to drop the target nodes'
        shell_cmd = f'''source {macro.DB_ENV_PATH};
                    expect <<EOF
                    set timeout 300
                    spawn gs_dropnode -U {self.sh['pri_user'].node.ssh_user} \
                    -G {self.sh['pri_user'].node.ssh_user} \
                    -h {self.sh.get("sta1_user").node.ssh_host}
                    expect "*(yes/no)?"
                    send "yes\\n"
                    expect eof''' + "\nEOF\n"
        self.log.info(shell_cmd)
        res = self.com.get_sh_result(self.sh['pri_user'].node, shell_cmd)
        self.assertIn(expect_msg, res, f'执行失败: {text}')

        text = '---预置步骤: 数据库主机解压安装包，以免找不到扩容脚本 expect: 成功---'
        self.log.info(text)
        cmd = f'cd {os.path.dirname(macro.DB_SCRIPT_PATH)} && ' \
            f'tar -xf openGauss-Package-bak*.tar.gz && ' \
            f'ls {macro.DB_SCRIPT_PATH}|grep gs_sshexkey'
        self.log.info(cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node, cmd)
        self.assertEqual(res, 'gs_sshexkey', f'执行失败: {text}')

        text = '----预置步骤: 创建测试表，插入测试数据 expect: 成功----'
        self.log.info(text)
        sql_cmd = f'drop table if exists {self.t_name};' \
            f'create table {self.t_name}(col1 int, col2 text);' \
            f'insert into {self.t_name} values ' \
            f'(generate_series(1,10000), generate_series(1,10000)||\'test\');'
        res = self.sh['pri_user'].executDbSql(sql_cmd)
        self.log.info(res)
        self.assertIn(self.cons.CREATE_TABLE_SUCCESS, res, f'执行失败: {text}')
        self.assertIn('INSERT 0 10000', res, f'执行失败: {text}')

        text = '----预置步骤: 建立root互信 expect: 成功----'
        self.log.info(text)
        ssh_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'echo "{self.sh.get("pri_root").node.ssh_host}\n' \
            f'{self.sh.get("sta1_user").node.ssh_host}\n' \
            f'{self.sh.get("sta2_user").node.ssh_host}" > hosts\n'
        ssh_cmd += f'''expect <<EOF
                            set timeout 300
                            spawn ./gs_sshexkey -f hosts
                            expect "*assword:"
                            send "{self.sh.get(
            "pri_root").node.ssh_password}\\n"
                            expect eof''' + "\nEOF\n"
        ssh_cmd += "source ~/.bashrc"
        self.log.info(ssh_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node, ssh_cmd)
        self.assertIn('Successfully created SSH trust', res, f'执行失败: {text}')

    def test_1(self):
        text = '----step1: 注入故障使待扩容备机磁盘空间不足 expect: 故障注入成功----'
        self.log.info(text)
        inject_cmd = f"rfile_full (diskname) values ({self.disk_name})"
        inject_res = self.com.cfe_inject(self.sh['sta1_root'].node, inject_cmd)
        self.log.info(inject_res)
        flg = "successful execution" in inject_res or \
              self.cons.FAILED_CONNECT_DB in inject_res
        self.assertTrue(flg, f'执行失败: {text}')

        text = '----step2: 备机扩容 expect: 备机扩容失败----'
        self.log.info(text)
        expansion_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'source {macro.DB_ENV_PATH}\n' \
            f'./gs_expansion -U {self.sh.get("pri_user").node.ssh_user} ' \
            f'-G {self.sh.get("pri_user").node.ssh_user} ' \
            f'-X {macro.DB_XML_PATH} ' \
            f'-h {self.sh.get("sta1_user").node.ssh_host} -L'
        self.log.info(expansion_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node,
                                     expansion_cmd)
        expansion_expect = 'Expansion results:.*:.*Success.*Expansion Finish.'
        regex_res = re.search(expansion_expect, res, re.S)
        self.assertIsNone(regex_res, f'执行失败: {text}')

        text = '----step3: 恢复备机故障 expect: 故障恢复成功----'
        self.log.info(text)
        clean_cmd = f"rfile_full where(diskname={self.disk_name})"
        clean_res = self.com.cfe_clean(self.sh['sta1_root'].node, clean_cmd)
        self.log.info(clean_res)
        self.assertIn("successful execution", clean_res, f'执行失败: {text}')

        text = '----step4: 备机扩容 expect: 备机扩容成功----'
        self.log.info(text)
        expansion_cmd = f'cd {macro.DB_SCRIPT_PATH};' \
            f'source {macro.DB_ENV_PATH}\n' \
            f'./gs_expansion -U {self.sh.get("pri_user").node.ssh_user} ' \
            f'-G {self.sh.get("pri_user").node.ssh_user} ' \
            f'-X {macro.DB_XML_PATH} ' \
            f'-h {self.sh.get("sta1_user").node.ssh_host} -L'
        self.log.info(expansion_cmd)
        res = self.com.get_sh_result(self.sh.get("pri_root").node,
                                     expansion_cmd)
        regex_res = re.search(expansion_expect, res, re.S)
        self.assertIsNotNone(regex_res, f'执行失败: {text}')

        text = '----step5: 查询数据库集群状态 expect: 数据库集群状态正常----'
        self.log.info(text)
        res = self.sh['pri_user'].getDbClusterStatus('detail')
        self.log.info(res)
        self.assertEqual(res.count('Normal'), self.node_num + 1,
                         f'执行失败: {text}')

        text = '----step6: 查看主备数据 expect: 数据一致----'
        self.log.info(text)
        nodes = (self.sh['pri_user'].node,
                 self.sh['sta1_user'].node,
                 self.sh['sta2_user'].node)
        flag = self.com.check_data_sample_by_all(r'\d', *nodes)
        self.assertTrue(flag)

        table_dict = self.com.format_sql_result(
            self.sh['pri_user'].executDbSql(r'\d'))
        table_name = table_dict.get('Name')
        for name in table_name:
            select_sql = f'select count(*) from {name};'
            flag = self.com.check_data_sample_by_all(select_sql,
                                                     *nodes)
            self.assertTrue(flag)

    def tearDown(self):
        text = '----run teardown----'
        self.log.info(text)

        text1 = f'----删除表----'
        self.log.info(text1)
        sql_cmd = f'drop table if exists {self.t_name};'
        res1 = self.sh['pri_user'].executDbSql(sql_cmd)
        self.log.info(res1)

        text2 = f'----检查集群状态是否正常----'
        self.log.info(text2)
        res2 = self.sh['pri_user'].getDbClusterStatus('detail')
        self.log.info(res2)

        self.assertIn(self.cons.DROP_TABLE_SUCCESS, res1, f'执行失败: {text1}')
        self.assertEqual(res2.count('Normal'), self.node_num + 1,
                         f'执行失败: {text2}')

        text = f'-----{os.path.basename(__file__)} end-----'
        self.log.info(text)
